#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
using namespace std;

#include "FlowSimGPU.h"
#include "VectorField2.h"
#include "ScalarField2.h"
#include "OgreTextureUnitState.h"
#include "OgreBitwise.h"
using namespace FlowSim;
using namespace Ogre;

//parameters used by jacobi iteration to determine alpha and rbeta for 
//the fragment program.
#define ALPHA_CUSTOM_PARAM 1
#define RBETA_CUSTOM_PARAM 2
#define SOURCES_CUSTOM_PARAM 1
#define DRATE_CUSTOM_PARAM 3
//0.00000713
MyFlowSimGpu::MyFlowSimGpu() : _dt(0.5),
			       _dim(256),
			       _vis(0.00000713),
			       _sgr(1.0),
			       _dyeDRate(0.99),
			       _resultRenderEnt(0),
			       _semiFullScreenQuad(0),
			       _fullScreenQuad(0),
			       _simPlaneEnt(0),
			       _playerNode(0),
			       _borderVelNode(0),
			       _borderPreNode(0),
			       _cam1(0),
			       _scnMgr(0),
			       _numJacPrj(50),
			       _numJacVis(30),
			       _gSX(1.0),
			       _gSY(1.0),
			       _fS0(0),
			       _fS1(0),
			       _fS2(0),
			       _fS3(0),
			       _fS4(0),
			       _thrust(0.0),
			       _curMis(0)
			     
{
  for(int i =0; i < MAX_MIS; i++)
    {
      _misThrusts[i] = 0.0;
      _misVis[i] = false;
    }
}
MyFlowSimGpu::~MyFlowSimGpu()
{
  delete _fullScreenQuad;
  //delete _semiFullScreenQuad;
  delete _fS0;
  delete _fS1;
  delete _fS2;
  delete _fS3;
  delete _fS4;
}

void MyFlowSimGpu::init(SceneManager* sMgr,RenderWindow* window)
{
  _scnMgr = sMgr;
  //creat the camera for render to texture
  Camera* mainCam = _scnMgr->getCamera("PlayerCam");
  _cam1 = _scnMgr->createCamera("RTTCam1");
  _cam1->setNearClipDistance(mainCam->getNearClipDistance());
  _cam1->setFarClipDistance(mainCam->getFarClipDistance());
  _cam1->setAspectRatio((Real)window->getViewport(0)->getActualWidth()/
		       (Real)window->getViewport(0)->getActualHeight());
  _cam1->setPosition(Vector3(0,0,200));
  createRenderTextures();
  setupRender();
}
/**
 *This method updates our simulation.
 **/
void MyFlowSimGpu::update()
{
  //cout << "MyFlowSimGpu::update()" << endl;
  _resultRenderEnt->setVisible(false);
  zeroPressureField(); //zero the pressure field.
  vorticityConf(); //do vorticity confinement
  advectVel(); //advect velocity
  boundaryVel(); //set the boundary conditions
  viscousDiffuseVel();
  project();
  forceSources(); //add force sources
  project(); //do projection operator
  boundaryVel(); //boundary velocity
  advectDye(); //advect dye
  renderGraphics(); //render graphics
  dyeSources(); 
  _resultRenderEnt->setVisible(true); //update render plane
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/resultMaterial"); 
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_dyef->getName());
 
}

void MyFlowSimGpu::reset()
{
	VectorField2::testGpuField(_vf,_dim);
}

void MyFlowSimGpu::advectVel()
{
  _fullScreenQuad->setVisible(true);
  //set the input texture into our advection material to be used by the advection shader.
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/advectionMaterial");
  GpuProgramParametersSharedPtr fragParams(mat->getTechnique(0)->getPass(0)->getFragmentProgramParameters());
  fragParams->setNamedConstant("drate",Real(1.0));

  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_vf->getName());
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName(_vf->getName());
  _fullScreenQuad->setMaterial("GpuFlowSim/advectionMaterial");
  //_semiFullScreenQuad->setMaterialName(0,"GpuFlowSim/advectionMaterial");
  RenderTarget* rtt = _tvf->getBuffer()->getRenderTarget();
  rtt->update();
  //swap velocity render textures
  swap(_vf,_tvf);
  copyTextureToRTT(_vf,_tvf);
  //_semiFullScreenNode->setVisible(false);
  _fullScreenQuad->setVisible(false);
}

void MyFlowSimGpu::advectDye()
{
   _fullScreenQuad->setVisible(true);
   //set the input texture into our advection material to be used by the advection shader.
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/advectionMaterial");
  GpuProgramParametersSharedPtr fragParams(mat->getTechnique(0)->getPass(0)->getFragmentProgramParameters());
  fragParams->setNamedConstant("drate",Real(_dyeDRate));
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_vf->getName());
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName(_dyef->getName());
  _fullScreenQuad->setMaterial("GpuFlowSim/advectionMaterial");
  RenderTarget* rtt = _tdyef->getBuffer()->getRenderTarget();
  rtt->update();
  //swap velocity render textures
  swap(_dyef,_tdyef);
  _fullScreenQuad->setVisible(false);
}

void MyFlowSimGpu::boundaryVel()
{
   _fullScreenQuad->setVisible(true);
   copyTextureToRTT(_vf,_tvf);
   _fullScreenQuad->setVisible(false);
  //set up the input textures for the borders.
  //left
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/leftBorderVelMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_vf->getName());
  //bottom
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/bottomBorderVelMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_vf->getName());
  //right
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/rightBorderVelMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_vf->getName());
  //up
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/topBorderVelMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_vf->getName());
  //render to texture 
  RenderTarget* rtt = _tvf->getBuffer()->getRenderTarget();
  Viewport *v = rtt->getViewport(0);
  v->setClearEveryFrame(false);
  _borderVelNode->setVisible(true);
  rtt->update();
  v->setClearEveryFrame(true);
  _borderVelNode->setVisible(false);
  swap(_vf,_tvf);
}

void MyFlowSimGpu::boundaryPre()
{
   _fullScreenQuad->setVisible(true);
  copyTextureToRTT(_pref,_tpref);
  _fullScreenQuad->setVisible(false);
  //set up the input textures for the borders.
  //left
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/leftBorderPreMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_pref->getName());
  //bottom
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/bottomBorderPreMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_pref->getName());
  //right
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/bottomBorderPreMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_pref->getName());
  //up
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/topBorderPreMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_pref->getName());
  //render to texture
  //copy content of _pref to _tpref
  RenderTarget* rtt = _tpref->getBuffer()->getRenderTarget();
  Viewport *v = rtt->getViewport(0);
  v->setClearEveryFrame(false);
  _borderPreNode->setVisible(true);
  rtt->update();
  v->setClearEveryFrame(true);
  _borderPreNode->setVisible(false);
  swap(_pref,_tpref);
}
/**
 *This method does the project operation. After projection we get a divergence free velocity field u.
 *We want to solve for a div free vector field u. By the Helmholtz decomposition,
 *u = w - grad p
 *Now we know Laplacian p = Del . w
 *Since w = u + Grad p, now apply the Divergence operator (Del .) to both sides to get,
 * Del . w = Del . (u + Del p)
 * Del . w = Del . u + Del^2 p
 * But Del . u = 0, by the Navier-Stokes equation for incompressible fluids. So we get,
 * Del . w = Del^2 p
 * We can solve for p using Jacobi iteration.
 * Once we know p we can solve u using the formula given above.
 **/
void MyFlowSimGpu::project()
{
  _semiFullScreenNode->setVisible(true);
  divergenceVel(); //compute divergence of velocity field.
  jacobiPressure(); //solve for pressure.
  _semiFullScreenNode->setVisible(false);
  boundaryPre();
  _semiFullScreenNode->setVisible(true);
  computeDivFreeField();
  _semiFullScreenNode->setVisible(false);
}

void MyFlowSimGpu::vorticityConf()
{
	_semiFullScreenNode->setVisible(true);
	MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/vortiPass1Material");
	mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_vf->getName()); //get u
	//pass 1
	_semiFullScreenQuad->setMaterialName(0,"GpuFlowSim/vortiPass1Material");
	RenderTarget* rtt=_vortf->getBuffer()->getRenderTarget();
	rtt->update();
	//pass 2
	mat = MaterialManager::getSingleton().getByName("GpuFlowSim/vortiPass2Material");
	mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_vortf->getName()); //get vort
	mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName(_vf->getName()); //get u
	_semiFullScreenQuad->setMaterialName(0,"GpuFlowSim/vortiPass2Material");
	rtt = _tvf->getBuffer()->getRenderTarget();
	rtt->update();
	swap(_vf,_tvf);
	_semiFullScreenNode->setVisible(false);
}

/**
 *This method computes the divergence of a velocity vector field, utilizing the GPU for computation.
 *This method setups the neccessary fragment program defined in GpuFlowSim/divergenceMaterial.
 *Renders to the _divw "Render To Texture" by using a full screen quad.
 *
 *Preconditions:
 *GpuFlowSim/divergenceMaterial is initialized, i.e texture unit exist.
 *_vf exists, and is current.
 *_fullScreenQuad exists and is visible. 
 *_divw exists.
 *PostConditions:
 *A scalar field is computed by the fragment program and is stored in the texture _divw.
 **/
void MyFlowSimGpu::divergenceVel()
{
  //setup the material for our frag program
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/divergenceMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_vf->getName()); //input is velocity field.
  //_semiFullScreenQuad->setMaterial("GpuFlowSim/divergenceMaterial");
  _semiFullScreenQuad->setMaterialName(0,"GpuFlowSim/divergenceMaterial");
  //_fullScreenQuad->setMaterial("GpuFlowSim/divergenceMaterial");
  RenderTarget* rtt = _divw->getBuffer()->getRenderTarget();
  rtt->update();
}
/**
 *This method implements Jacobi iteration to specifically solve for the pressure field p.
 *This method setups the neccessary uniform fragment shader variables as related to solving for pressure p.
 *In our formulation of the Jacobi iteration, we require two varibles
 *alpha and rbeta. For the projection operator, we know that:
 *Laplacian p = Divergence W.
 *So we formulate the Jacobi iteration to solve the Possion pressure equation
 *in the given form Ax = b such that:
 * PUT EXPLANATION HERE
 * BLAH BLAH BLAH
 * BLAH BLAH BLAH
 *alpha = -(dx)^2 rBeta = 1/4
 **/
void MyFlowSimGpu::jacobiPressure()
{
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/jacobiMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName(_divw->getName()); //b in Ax=b
  //_fullScreenQuad->setMaterial("GpuFlowSim/jacobiMaterial");
  _semiFullScreenQuad->setMaterialName(0,"GpuFlowSim/jacobiMaterial");
  GpuProgramParametersSharedPtr fragParams(mat->getTechnique(0)->getPass(0)->getFragmentProgramParameters());
  fragParams->setNamedConstant("alpha",-(_gSX*_gSX));
  fragParams->setNamedConstant("rbeta",Real(1.0/4.0));
  //_fullScreenQuad->setCustomParameter(ALPHA_CUSTOM_PARAM,Vector4(-(_gSX*_gSX),0.0,0.0,0.0));
  //_fullScreenQuad->setCustomParameter(RBETA_CUSTOM_PARAM,Vector4(1.0/4.0,0.0,0.0,0.0));
  int i=0;
  RenderTarget* rtt;
  while(i < _numJacPrj)
    {
      mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_pref->getName()); //x in Ax=b
      rtt = _tpref->getBuffer()->getRenderTarget();
      rtt->update();
      swap(_pref,_tpref);
      ++i;
    }
}

void MyFlowSimGpu::computeDivFreeField()
{
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/gradSubMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_pref->getName()); //For Grad p
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName(_vf->getName()); //for w in u = w-grad p
  _semiFullScreenQuad->setMaterialName(0,"GpuFlowSim/gradSubMaterial");
  //_fullScreenQuad->setMaterial("GpuFlowSim/gradSubMaterial");
  RenderTarget* rtt = _tvf->getBuffer()->getRenderTarget();
  rtt->update();
  swap(_vf,_tvf);
}

void MyFlowSimGpu::viscousDiffuseVel()
{
  _semiFullScreenQuad->setVisible(true);
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/jacobiMaterial");
  _semiFullScreenQuad->setMaterialName(0,"GpuFlowSim/jacobiMaterial");
  Real temp = (_gSX*_gSX)/(_vis*_dt);
  GpuProgramParametersSharedPtr fragParams(mat->getTechnique(0)->getPass(0)->getFragmentProgramParameters());
  fragParams->setNamedConstant("alpha",temp);
  fragParams->setNamedConstant("rbeta",Real(1.0/(4+temp)));
//   _fullScreenQuad->setCustomParameter(ALPHA_CUSTOM_PARAM,Vector4(temp,0.0,0.0,0.0));
//   _fullScreenQuad->setCustomParameter(RBETA_CUSTOM_PARAM,Vector4(1.0/(4+temp),0.0,0.0,0.0));
  int i = 0;
  RenderTarget* rtt;
  
  while(i < _numJacVis)
    {
      mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName(_vf->getName()); //b = Ax=b
      mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(_vf->getName());
      rtt = _tvf->getBuffer()->getRenderTarget();
      rtt->update();
      swap(_vf,_tvf);
      ++i;
    }
   _semiFullScreenQuad->setVisible(false);
}

void MyFlowSimGpu::forceSources()
{
 
  _force0.x = -50.0;
  _force0.y = 0.0;
  _force0.z = 0.0;
  _force0.w = 0.0;
  
  _fS0->setCustomParameter(SOURCES_CUSTOM_PARAM,_force0);
  _forceSourcesNode->setVisible(true);

  _force0.x = -0.0;
  _force0.y = 10.0;
  _force0.z = 0.0;
  _force0.w = 0.0;

  _fS1->setCustomParameter(SOURCES_CUSTOM_PARAM,_force0);

  //setup player
  Vector3 force = Vector3(0.0,0.0,1.0);
  force = _playerNode->getLocalAxes().GetColumn(2);
  force *= _thrust+30.0;
  force.x *= -1;
  _playerEntity->setMaterialName("GpuFlowSim/sourcesMaterial");
  SubEntity* sub = _playerEntity->getSubEntity(0);
  sub->setCustomParameter(SOURCES_CUSTOM_PARAM,Vector4(force.x,force.y,force.z,0.0));
  _playerNode->setVisible(true);

  startMissilesVel();
  RenderTarget* rtt = _vf->getBuffer()->getRenderTarget();
  Viewport *v = rtt->getViewport(0);
 
  v->setClearEveryFrame(false);
  rtt->update();
  v->setClearEveryFrame(true);
  _forceSourcesNode->setVisible(false);
  _playerNode->setVisible(false);
  endMissiles();
  _playerEntity->setMaterialName("RZR-002");
}

void MyFlowSimGpu::dyeSources()
{
  _force1.x = 1.0;
  _force1.y = 0.0;
  _force1.z = 0.0;
  _force1.w = 1.0;

  _fS3->setCustomParameter(SOURCES_CUSTOM_PARAM,_force1);
  
  _force1.x = 0.0;
  _force1.y = 0.0;
  _force1.z = 1.0;
  _force1.w = 1.0;
  
  _fS2->setCustomParameter(SOURCES_CUSTOM_PARAM,_force1);

  _force1.x = 0.0;
  _force1.y = 1.0;
  _force1.z = 1.0;
  _force1.w = 1.0;

  _fS4->setCustomParameter(SOURCES_CUSTOM_PARAM,_force1);

  

  _dyeSourcesNode->setVisible(true);
  RenderTarget* rtt = _dyef->getBuffer()->getRenderTarget();
  Viewport *v = rtt->getViewport(0);
  //cout << "Got viewport" << endl;
  v->setClearEveryFrame(false);
  rtt->update();
  v->setClearEveryFrame(true);
  _dyeSourcesNode->setVisible(false);
 
}

void MyFlowSimGpu::renderGraphics()
{
  _playerNode->setVisible(true);
  //_playerNode->setPosition(Vector3(0.0,0.0,-5.0));
  _playerNode->translate(_playerNode->getOrientation()*Vector3(0,0,_thrust));
  //_playerNode->translate(_playerNode->getLocalAxes(),Vector3(0,0,1.0));

  startMissilesDye();

  RenderTarget* rtt = _dyef->getBuffer()->getRenderTarget();
  Viewport *v = rtt->getViewport(0);
  
  v->setClearEveryFrame(false);
  rtt->update();
  v->setClearEveryFrame(true);
  _playerNode->setVisible(false);

  endMissiles();
}

void MyFlowSimGpu::yaw(Real x)
{
  _playerNode->yaw(Degree(x));
}

void MyFlowSimGpu::trust(Real x)
{
  _thrust += x;
  if(_thrust <= 0.0)
    _thrust = 0.0;
}

void MyFlowSimGpu::swap(TexturePtr &tx1, TexturePtr &tx2)
{
  TexturePtr tmp = tx2;
  tx2 = tx1;
  tx1 = tmp;
}

void MyFlowSimGpu::zeroPressureField()
{
   _fullScreenQuad->setVisible(true);
  //Material mat = MaterialManager::getSingleton().getByName("GpuFlowSim/zeroFieldMaterial");
  _fullScreenQuad->setMaterial("GpuFlowSim/zeroFieldMaterial");
  RenderTarget* rtt;
  rtt = _pref->getBuffer()->getRenderTarget();
  rtt->update();
  _fullScreenQuad->setVisible(false);
}

void MyFlowSimGpu::copyTextureToRTT(const TexturePtr &tex, const TexturePtr &rttTex)
{
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/copyFieldMaterial");
  mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(tex->getName());
  _fullScreenQuad->setMaterial("GpuFlowSim/copyFieldMaterial");      
  //_semiFullScreenQuad->setMaterialName(0,"GpuFlowSim/copyFieldMaterial");    
  RenderTarget* rtt = rttTex->getBuffer()->getRenderTarget();
  rtt->update();
}


/**
 *This method creates the render to textures. Render to textures are neccessary in our implemenation, 
 *so to utilize the GPU for computation of fluid simulation.
 **/
void MyFlowSimGpu::createRenderTextures()
{
  //create the render target textures for our velocity fields
  
  _vf = TextureManager::getSingleton().createManual("VFTex",
						    ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,TEX_TYPE_2D,
						    _dim,_dim,0,PF_FLOAT16_RGBA,TU_RENDERTARGET);
  _tvf = TextureManager::getSingleton().createManual("VFTempTex",ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
						     TEX_TYPE_2D,_dim,_dim,0,PF_FLOAT16_RGBA,TU_RENDERTARGET);
  //create the render target texture for divergence of a vector field w.
  _divw = TextureManager::getSingleton().createManual("DIVWTex",
						      ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,TEX_TYPE_2D,
						      _dim,_dim,0,PF_FLOAT16_RGBA,TU_RENDERTARGET);
  _pref = TextureManager::getSingleton().createManual("PREFTex",
						      ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,TEX_TYPE_2D,
						      _dim,_dim,0,PF_FLOAT16_RGBA,TU_RENDERTARGET);
  _tpref = TextureManager::getSingleton().createManual("PREFTempTex",
						       ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,TEX_TYPE_2D,
						       _dim,_dim,0,PF_FLOAT16_RGBA,TU_RENDERTARGET);
  
  _dyef = TextureManager::getSingleton().createManual("DYEFTex",
						      ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,TEX_TYPE_2D,
						      _dim,_dim,0,PF_FLOAT16_RGBA,TU_RENDERTARGET);
  _tdyef = TextureManager::getSingleton().createManual("DYEFTempTex",
						       ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,TEX_TYPE_2D,
						       _dim,_dim,0,PF_FLOAT16_RGBA,TU_RENDERTARGET);
   _vortf = TextureManager::getSingleton().createManual("VORTFTex",ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
							TEX_TYPE_2D,_dim,_dim,0,PF_FLOAT16_RGB,TU_RENDERTARGET);
	
//  TexturePtr test = TextureManager::getSingleton().createManual("TestTempTex",
// 						       ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,TEX_TYPE_2D,
// 						       _dim,_dim,0,PF_BYTE_RGBA,TU_RENDERTARGET);

  _cam1->setPosition(0.0,0.0,0.0);
//   RenderTarget* rttTex = test->getBuffer()->getRenderTarget();
//   Viewport *v = rttTex->addViewport(_cam1);
//   v->setClearEveryFrame(true);
//   v->setBackgroundColour(ColourValue::White);
  // rttTex->setAutoUpdated(false);


  //Setup the rendertarget for vf and tvf
  _cam1->setPosition(0.0,0.0,500.0);
  setupRTT(_vf,_cam1);
  setupRTT(_tvf,_cam1);
  VectorField2::testGpuField(_vf,_dim); //load inital vector field for _vf
  //VectorField2::testGpuField(_vf,_dim);
  LogManager::getSingleton().logMessage("VF Before testGpuField.");
  //debugOutBorders(_vf);
  //VectorField2::testGpuField(_vf,_dim);
  //debugOutBorders(_vf);
  LogManager::getSingleton().logMessage("VF After testGpuField.");
  //setup divergence of w
  setupRTT(_divw,_cam1);
  setupRTT(_pref,_cam1);
  setupRTT(_tpref,_cam1);
  setupRTT(_dyef,_cam1);
  //VectorField2::blankGpuField(_dyef,_dim);
  setupRTT(_tdyef,_cam1);
  setupRTT(_vortf,_cam1);
}

void MyFlowSimGpu::setupRender()
{
  SceneNode *rootNode = _scnMgr->getRootSceneNode();
  SceneNode* node;
  //create the result render node
  Plane plane(Vector3::UNIT_Z,0);
  MeshManager::getSingleton().createPlane("ResultPlane",ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,plane,
					  _dim,_dim,1,1,true,1,1,1,Vector3::UNIT_Y);
  _resultRenderEnt = _scnMgr->createEntity("ResultPlaneEnt","ResultPlane");
  node = rootNode->createChildSceneNode("ResultNode");
  node->attachObject(_resultRenderEnt);
  node->setPosition(Vector3(0,0,-300));
  
  
  Real ds=1.0/_dim*2.0;
  //create full screen quad 
  _fullScreenQuad = new Rectangle2D(true);
  _fullScreenQuad->setCorners(-1.0,1.0,1.0,-1.0);
  _fullScreenQuad->setVisible(false);
  node = rootNode->createChildSceneNode("FullScreenQuadNode");
  node->attachObject(_fullScreenQuad);

  //create test plane
  _playerEntity = _scnMgr->createEntity("PlayerEnt","razor.mesh");
  _playerNode = rootNode->createChildSceneNode("PlayerNode");
  _playerNode->attachObject(_playerEntity);
  _playerNode->setPosition(0.0,0.0,-10.0);
  _playerNode->yaw(Degree(90.0));
  _playerNode->roll(Degree(-90.0));
  //_playerNode->pitch(Degree(90.0));
  _playerNode->setScale(0.13,0.13,0.13);
  _playerNode->setVisible(false);

  //create missles
  createMissiles();
  
  //setup the materials
  setupMaterials();

  //make sure you create the velocity borders before calling update, since update also updates the boundary.
  createVelBorders();
  createForceSources();
  createSemiFullScreenQuad();
  //boundaryVel();
  //testManual2();
  //update();   
}


void MyFlowSimGpu::createVelBorders()
{
  ManualObject* velMan = _scnMgr->createManualObject("velBorders");
  ManualObject* preMan = _scnMgr->createManualObject("preBorders");
  //use the identity view/projection matrices
  velMan->setUseIdentityProjection(true);
  velMan->setUseIdentityView(true);
  preMan->setUseIdentityProjection(true);
  preMan->setUseIdentityView(true);
  velMan->setDynamic(true);
  preMan->setDynamic(true);
  Real offset = 1.0/_dim*2.0;
  Real toffset = 1.0/_dim;
  Vector3 temp;
  Vector2 tex;
  temp.z = 0.0;
  MaterialPtr mat = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting");
  mat->setDepthCheckEnabled(false);
  //left border
  velMan->begin("GpuFlowSim/leftBorderVelMaterial",
		RenderOperation::OT_TRIANGLE_LIST);
  preMan->begin("GpuFlowSim/leftBorderPreMaterial",
		RenderOperation::OT_TRIANGLE_LIST);
//   velMan->begin("BaseWhiteNoLighting",
// 		RenderOperation::OT_TRIANGLE_LIST);
//   preMan->begin("BaseWhiteNoLighting",
// 		RenderOperation::OT_TRIANGLE_LIST);
  //top left corner
  temp.x = -1.0; temp.y = 1.0;
  tex.x = 0.0; tex.y = 0.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //lower left corner
  temp.x=-1.0;temp.y=-1.0;
  tex.x=0.0;tex.y=1.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //lower right corner
  temp.x=-1.0+offset;temp.y=-1.0;
  tex.x=toffset;tex.y=1.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //top right corner
  temp.x = -1.0+offset; temp.y = 1.0;
  tex.x = toffset; tex.y = 0.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  
  velMan->quad(0,1,2,3);
  preMan->quad(0,1,2,3);
  velMan->end();
  preMan->end();
  //bottom border
  velMan->begin("GpuFlowSim/bottomBorderVelMaterial",
		RenderOperation::OT_TRIANGLE_LIST);
  preMan->begin("GpuFlowSim/bottomBorderPreMaterial",
		RenderOperation::OT_TRIANGLE_LIST);
//   velMan->begin("BaseWhiteNoLighting",
// 		RenderOperation::OT_TRIANGLE_LIST);
//   preMan->begin("BaseWhiteNoLighting",
// 		RenderOperation::OT_TRIANGLE_LIST);
  //top left corner
  temp.x = -1.0; temp.y = -1.0+offset;
  tex.x = 0.0; tex.y = 1.0-toffset;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //lower left corner
  temp.x=-1.0;temp.y=-1.0;
  tex.x=0.0;tex.y=1.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //lower right corner
  temp.x=1.0;temp.y=-1.0;
  tex.x=1.0;tex.y=1.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //top right corner
  temp.x = 1.0; temp.y = -1.0+offset;
  tex.x = 1.0; tex.y = 1.0-toffset;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  
  velMan->quad(0,1,2,3);
  preMan->quad(0,1,2,3);
  velMan->end();
  preMan->end();

  //top border
  velMan->begin("GpuFlowSim/topBorderVelMaterial",
		RenderOperation::OT_TRIANGLE_LIST);
  preMan->begin("GpuFlowSim/topBorderPreMaterial",
		RenderOperation::OT_TRIANGLE_LIST);
//   velMan->begin("BaseWhiteNoLighting",
// 		RenderOperation::OT_TRIANGLE_LIST);
//   preMan->begin("BaseWhiteNoLighting",
// 		RenderOperation::OT_TRIANGLE_LIST);
  //top left corner
  temp.x = -1.0; temp.y = 1.0;
  tex.x = 0.0; tex.y = 0.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //lower left corner
  temp.x=-1.0;temp.y=1.0-offset;
  tex.x=0.0;tex.y=0.0+toffset;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //lower right corner
  temp.x=1.0;temp.y=1.0-offset;
  tex.x=1.0;tex.y=0.0+toffset;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //top right corner
  temp.x = 1.0; temp.y = 1.0;
  tex.x = 1.0; tex.y = 0.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  
  velMan->quad(0,1,2,3);
  preMan->quad(0,1,2,3);
  velMan->end();
  preMan->end();
  //right border
  velMan->begin("GpuFlowSim/rightBorderVelMaterial",
		RenderOperation::OT_TRIANGLE_LIST);
  preMan->begin("GpuFlowSim/rightBorderPreMaterial",
		RenderOperation::OT_TRIANGLE_LIST);
 //  velMan->begin("BaseWhiteNoLighting",
// 		RenderOperation::OT_TRIANGLE_LIST);
//   preMan->begin("BaseWhiteNoLighting",
// 		RenderOperation::OT_TRIANGLE_LIST);
  //top left corner
  temp.x = 1.0-offset; temp.y = 1.0;
  tex.x = 1.0-toffset; tex.y = 0.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //lower left corner
  temp.x=1.0-offset;temp.y=-1.0;
  tex.x=1.0-toffset;tex.y=1.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //lower right corner
  temp.x=1.0;temp.y=-1.0;
  tex.x=1.0;tex.y=1.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  //top right corner
  temp.x = 1.0; temp.y = 1.0;
  tex.x = 1.0; tex.y = 0.0;
  velMan->position(temp);
  preMan->position(temp);
  velMan->textureCoord(tex);
  preMan->textureCoord(tex);
  
  velMan->quad(0,1,2,3);
  preMan->quad(0,1,2,3);
  velMan->end();
  preMan->end();

  AxisAlignedBox aabInf;
  aabInf.setInfinite();
  velMan->setBoundingBox(aabInf);
  preMan->setBoundingBox(aabInf);
  velMan->setRenderQueueGroup(RENDER_QUEUE_OVERLAY-1);
  preMan->setRenderQueueGroup(RENDER_QUEUE_OVERLAY-1);
  //create the scene node
  _borderVelNode = _scnMgr->getRootSceneNode()->createChildSceneNode();
  _borderPreNode = _scnMgr->getRootSceneNode()->createChildSceneNode();
  _borderVelNode->attachObject(velMan);
  _borderPreNode->attachObject(preMan);
  _borderVelNode->setVisible(false);
  _borderPreNode->setVisible(false);
  //load the border textures
  loadBordersMaterialTexture();
  
  
}

/**
 *This method sets up render to texture, given a textureptr tex and a camera.
 **/
void MyFlowSimGpu::setupRTT(const TexturePtr &tex, Camera* cam)
{
  RenderTarget* rttTex = tex->getBuffer()->getRenderTarget();
  Viewport *v = rttTex->addViewport(cam);
  v->setClearEveryFrame(true);
  v->setBackgroundColour(ColourValue::White);
  rttTex->setAutoUpdated(false);
}
/**
 *This method loads default textures into the border materials
 **/
void MyFlowSimGpu::loadBordersMaterialTexture()
{
  assert(!(_vf.isNull()) && "velocity field empty!");
  assert(!(_tvf.isNull()) && "temp velocity field is empty!");
  //left border
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/leftBorderVelMaterial");
  mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/leftBorderPreMaterial");
  mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  //bottom border
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/bottomBorderVelMaterial");
  mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/bottomBorderPreMaterial");
  mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  //right border
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/rightBorderVelMaterial");
  mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/rightBorderPreMaterial");
  mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  //top
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/topBorderVelMaterial");
  mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/topBorderPreMaterial");
  mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
}

void MyFlowSimGpu::setupMaterials()
{
  assert(!(_vf.isNull()) && "velocity field is null!");
  assert((_resultRenderEnt != 0) && "_resultRenderEnt is null");
  MaterialPtr mat = MaterialManager::getSingleton().getByName("GpuFlowSim/resultMaterial");
  mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  _resultRenderEnt->setMaterialName("GpuFlowSim/resultMaterial");

  //remember we initialize the material with a default texture (_vf), but we change them later
  //when we actually use them. With set the default texture here so we don't load unncessary 
  //textures, which is what would happen if we use some sort of default texture in the material script.
  //setup advection material
  assert((_fullScreenQuad != 0) && "_fullScreenQuad is null!");
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/advectionMaterial");
  TextureUnitState *t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
  //setup divergence material
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/divergenceMaterial");
  t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
  //setup graidentsub material
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/gradSubMaterial");
  t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
  t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
  //setup jacobi material
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/jacobiMaterial");
  t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
  t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
  //setup copyfield material
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/copyFieldMaterial");
  t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
  //setup vorticity material
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/vortiPass1Material");
  t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
  mat = MaterialManager::getSingleton().getByName("GpuFlowSim/vortiPass2Material");
  t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
  t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(_vf->getName());
  t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
}
/**
 *This method creates force sources. Sources that emanate forces into the velocity field.
 **/
void MyFlowSimGpu::createForceSources()
{
  SceneNode* rootNode = _scnMgr->getRootSceneNode();
  SceneNode* node;
  
  Real ds = 1.0/_dim*2.0;;
  //create a source near the right
  //auto_ptr<Rectangle2D> ap(new Rectangle2D(true));
  _fS0 = new Rectangle2D(true);
  _fS1 = new Rectangle2D(true);
  _fS2 = new Rectangle2D(true);
  _fS3 = new Rectangle2D(true);
  _fS4 = new Rectangle2D(true);
  Real l = 1.0-(ds*2);
  Real t = 1.0-(ds);
  Real r = 1.0-(ds);
  Real d = 1.0-(ds*2);
  
  MaterialPtr m = MaterialManager::getSingleton().getByName("GpuFlowSim/sourcesMaterial");
  

  _fS0->setCorners(0.8,0.0,0.8+ds*5,0.0-ds*5);
  _fS0->setMaterial("GpuFlowSim/sourcesMaterial");

  m->clone("GpuFlowSim/sourcesMaterial1"); 
  _fS1->setCorners(0.4,0.2,0.4+ds*4,0.0-ds);
  _fS1->setMaterial("GpuFlowSim/sourcesMaterial1");

  m->clone("GpuFlowSim/sourcesMaterial2");
  _fS2->setCorners(0.0,0.0,0.1,-0.1); 
  _fS2->setMaterial("GpuFlowSim/sourcesMaterial2");

  m->clone("GpuFlowSim/sourcesMaterial3");
  _fS3->setCorners(0.8,0.0,0.8+ds*5,0.0-ds*5);
  _fS3->setMaterial("GpuFlowSim/sourcesMaterial3");

  m->clone("GpuFlowSim/sourcesMaterial4"); 
  _fS4->setCorners(0.4,0.2,0.4+ds*4,0.2-ds);
  _fS4->setMaterial("GpuFlowSim/sourcesMaterial1");

  _forceSourcesNode = rootNode->createChildSceneNode("ForceSourcesMainNode");
  _forceSourcesNode->attachObject(_fS0);
  _forceSourcesNode->attachObject(_fS1);
  //_forceSourcesNode->attachObject(_fS1);
  _forceSourcesNode->setVisible(false);
  _dyeSourcesNode = rootNode->createChildSceneNode("DyeSourcesMainNode");
  _dyeSourcesNode->attachObject(_fS3);
  _dyeSourcesNode->attachObject(_fS2);
  _dyeSourcesNode->attachObject(_fS4);
  _dyeSourcesNode->setVisible(false);
}



void MyFlowSimGpu::createSemiFullScreenQuad()
{
  _semiFullScreenQuad = _scnMgr->createManualObject("SemiFullScreenQuad");
  
  
  _semiFullScreenQuad->setUseIdentityProjection(true);
  _semiFullScreenQuad->setUseIdentityView(true);
  _semiFullScreenQuad->setDynamic(true);
 
  Real offset = 1.0/_dim*2.0;
  Real toffset = 1.0/_dim;
  Vector3 temp;
  Vector2 tex;
  temp.z = 0.0;
  MaterialPtr mat = MaterialManager::getSingleton().getByName("Examples/Rockwall");
  mat->setDepthCheckEnabled(false);
  
  _semiFullScreenQuad->begin("Examples/Rockwall",
			     RenderOperation::OT_TRIANGLE_LIST);
  //vert upper left
  temp.x = -1.0+offset; temp.y = 1.0-offset;
  tex.x = toffset; tex.y = toffset;
  _semiFullScreenQuad->position(temp);
  _semiFullScreenQuad->textureCoord(tex);
  //vert lower left
  temp.x = -1.0+offset; temp.y = -1.0+offset;
  tex.x = toffset; tex.y = 1.0-toffset;
  _semiFullScreenQuad->position(temp);
  _semiFullScreenQuad->textureCoord(tex);
  //vert lower right
  temp.x = 1.0-offset; temp.y = -1.0+offset;
  tex.x = 1.0-toffset; tex.y = 1.0-toffset;
  _semiFullScreenQuad->position(temp);
  _semiFullScreenQuad->textureCoord(tex);
  //vert upper right
  temp.x = 1.0-offset; temp.y = 1.0-offset;
  tex.x = 1.0-toffset; tex.y = toffset;
  _semiFullScreenQuad->position(temp);
  _semiFullScreenQuad->textureCoord(tex);

  _semiFullScreenQuad->quad(0,1,2,3);
  _semiFullScreenQuad->end();

  // Use infinite AAB to always stay visible
  AxisAlignedBox aabInf;
  aabInf.setInfinite();
  _semiFullScreenQuad->setBoundingBox(aabInf);

  //semi->convertToMesh("SemiFullScreenQuadMesh");
  //_scnMgr->destroyManualObject(semi);
  
  //_semiFullScreenQuad = _scnMgr->createEntity("SemiFullScreenEnt","SemiFullScreenQuadMesh");
  
  // Render just before overlays
  //_semiFullScreenQuad->setRenderQueueGroup(RENDER_QUEUE_OVERLAY - 1);
 
  //_semiFullScreenNode = _scnMgr->getRootSceneNode()->createChildSceneNode("SemiFullScreenNode");
  _semiFullScreenNode = _scnMgr->getRootSceneNode()->createChildSceneNode("SemiFullScreenNode");
  _semiFullScreenNode->attachObject(_semiFullScreenQuad);
  //_semiFullScreenNode->setUseIdentityProjection(true);
  //_semiFullScreenNode->setUseIdentityView(true);
  _semiFullScreenNode->setVisible(false);
}

void MyFlowSimGpu::debugOutBorders(const TexturePtr tex)
{
  ostringstream oss;
  LogManager::getSingleton().logMessage("MyFlowSimGpu::debugOutBorders:");
  HardwarePixelBufferSharedPtr hb = tex->getBuffer(0,0);
  hb->lock(HardwareBuffer::HBL_NORMAL);
  const PixelBox &pb = hb->getCurrentLock();
  uint16 *data = static_cast<uint16*>(pb.data);
  size_t height = pb.getHeight();
  size_t width = pb.getWidth();
  size_t pitch = pb.rowPitch;

  LogManager::getSingleton().logMessage("---------Left border:--------------- ");
  size_t st = 0;
  size_t offset = 1;
  size_t size = 4;
  Real temp1r, temp1g, temp2r, temp2g;
  //size_t y = 0;
  
 //  temp1r = Bitwise::halfToFloat(data[pitch*1+st*4]);
//   temp1g = Bitwise::halfToFloat(data[pitch*1+st*4+1]);
//   oss << temp1r << " " << temp1g << " pitch: " << pitch <<  endl;
  
  LogManager::getSingleton().logMessage(oss.str());
  for(size_t y=0; y<height; ++y)
    {
      oss << "x,y: " << st << " " << y << endl;
      LogManager::getSingleton().logMessage(oss.str());
      oss.str("");
      temp1r = Bitwise::halfToFloat(data[pitch*y+st*size]); //r
      temp1g = Bitwise::halfToFloat(data[pitch*y+st*size+1]); //g
      temp2r = Bitwise::halfToFloat(data[pitch*y+(st+offset)*size]); //r
      temp2g = Bitwise::halfToFloat(data[pitch*y+(st+offset)*size+1]); //g
      oss << "b: " << temp1r << " " << temp1g << endl;
      LogManager::getSingleton().logMessage(oss.str());
      oss.str("");
      oss << "c: " << temp2r << " " << temp2g << endl;
      LogManager::getSingleton().logMessage(oss.str());
      oss.str("");
    }
  //  LogManager::getSingleton().logMessage("---------right border:--------------- ");
//    st = width-1; offset = -1;
//    for(size_t y=0; y<height; ++y)
//      {
//        oss << "x,y: " << st << " " << y << endl;
//        LogManager::getSingleton().logMessage(oss.str());
//        oss.str("");
//        temp1r = Bitwise::halfToFloat(data[pitch*y*size+st*size]); //r
//        temp2g = Bitwise::halfToFloat(data[pitch*y*size+st*size+1]); //g
//        temp2r = Bitwise::halfToFloat(data[pitch*y*size+(st+offset)*size]); //r
//        temp2g = Bitwise::halfToFloat(data[pitch*y*size+(st+offset)*size+1]); //g
//        oss << "b: " << temp1r << " " << temp1g << endl;
//        LogManager::getSingleton().logMessage(oss.str());
//        oss.str("");
//        oss << "c: " << temp2r << " " << temp2g << endl;
//        LogManager::getSingleton().logMessage(oss.str());
//        oss.str("");
//      }
//    LogManager::getSingleton().logMessage("---------bottom border:--------------- ");
//    st = 0; offset = 1;
//    for(size_t x=0; x<width; ++x)
//      {
 //       oss << "x,y: " << x << " " << st << endl;
//        LogManager::getSingleton().logMessage(oss.str());
//        oss.str("");
//        temp1r = Bitwise::halfToFloat(data[pitch*st*size+x*size]); //r
//        temp2g = Bitwise::halfToFloat(data[pitch*st*size+x*size+1]); //g
//        temp2r = Bitwise::halfToFloat(data[pitch*(st+offset)*size+x*size]); //r
//        temp2g = Bitwise::halfToFloat(data[pitch*(st+offset)*size+x*size+1]); //g
//        oss << "b: " << temp1r << " " << temp1g << endl;
//        LogManager::getSingleton().logMessage(oss.str());
//        oss.str("");
//        oss << "c: " << temp2r << " " << temp2g << endl;
//        LogManager::getSingleton().logMessage(oss.str());
//        oss.str("");
//      }
//    LogManager::getSingleton().logMessage("---------top border:--------------- ");
//     st = height-1; offset = -1;
//    for(size_t x=0; x<width; ++x)
//      {
//        oss << "x,y: " << x << " " << st << endl;
//        LogManager::getSingleton().logMessage(oss.str());
//        oss.str("");
//        temp1r = Bitwise::halfToFloat(data[pitch*st*size+x*size]); //r
//        temp2g = Bitwise::halfToFloat(data[pitch*st*size+x*size+1]); //g
//        temp2r = Bitwise::halfToFloat(data[pitch*(st+offset)*size+x*size]); //r
//        temp2g = Bitwise::halfToFloat(data[pitch*(st+offset)*size+x*size+1]); //g
//        oss << "b: " << temp1r << " " << temp1g << endl;
//        LogManager::getSingleton().logMessage(oss.str());
//        oss.str("");
//        oss << "c: " << temp2r << " " << temp2g << endl;
//        LogManager::getSingleton().logMessage(oss.str());
//        oss.str("");
//      }
   
  hb->unlock();

}

void MyFlowSimGpu::createMissiles()
{
  ManualObject* man = _scnMgr->createManualObject("ManualObject");

  //MaterialPtr mat = MaterialManager::getSingleton().getByName("Examples/Rockwall");
  //mat->setDepthCheckEnabled(false);
  Real size = 10.0;
  Vector3 start(-5,0.0,5);
  Vector2 sTex(0.0,0.0);
  MaterialPtr mat = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting");
  mat->setDepthCheckEnabled(false);
  
  man->begin("BaseWhiteNoLighting",RenderOperation::OT_TRIANGLE_LIST);

  //upper left
  man->position(start);
  man->textureCoord(sTex);
  //lower left
  man->position(start+Vector3(0.0,size,0.0));
  man->textureCoord(sTex+Vector2(0.0,size));
  //lower right
  man->position(start+Vector3(size,size,0.0));
  man->textureCoord(sTex+Vector2(size,size));
  //upper right
  man->position(start+Vector3(size,0.0,0.0));
  man->textureCoord(sTex+Vector2(size,0.0));
  man->quad(0,1,2,3);
  man->end();
  man->convertToMesh("MissleMesh");
  _scnMgr->destroyManualObject(man);
  
  char name[20];
  SceneNode* root = _scnMgr->getRootSceneNode();
  for(int i=0; i < MAX_MIS; i++)
    {
      sprintf(name,"MIS_ENT%d",i);
      _missileEntities[i] = _scnMgr->createEntity(name,"MissleMesh");
      _missleNodes[i] = root->createChildSceneNode();
      _missleNodes[i]->attachObject(_missileEntities[i]);
      _missleNodes[i]->setVisible(false);
      //rotate into player space
      _missleNodes[i]->setPosition(_playerNode->getPosition());
      _missleNodes[i]->setOrientation(_playerNode->getOrientation());
    } 
}

void MyFlowSimGpu::startMissilesVel()
{
  Vector3 force;
  for(int i=0; i < MAX_MIS; i++)
    {
      if(_misVis[i])
	{
	  force.x = 0.0;
	  force.y = 0.0;
	  force.z = _misThrusts[i];
	  force = _missleNodes[i]->getOrientation()*force;
	  _missleNodes[i]->setVisible(true);
	  _missleNodes[i]->translate(force);
	  _missileEntities[i]->setMaterialName("GpuFlowSim/sourcesMaterial");
	  _missleNodes[i]->setCustomParameter(SOURCES_CUSTOM_PARAM,Vector4(force.x,force.y,force.z,0.0));
	  
	}
    }
}
void MyFlowSimGpu::startMissilesDye()
{
  
  for(int i=0; i < MAX_MIS; i++)
    {
      if(_misVis[i])
	{
	  _missleNodes[i]->setVisible(true);
	  
	  _missileEntities[i]->setMaterialName("BaseWhiteNoLighting");
	}
    }
}
void MyFlowSimGpu::endMissiles()
{
  for(int i=0; i<MAX_MIS;i++)
    {
      if(_misVis[i])
	{
	  _missleNodes[i]->setVisible(false);
	}
    }
}

void MyFlowSimGpu::fireMissile()
{
  int cur = _curMis++;
  if(_curMis == MAX_MIS)
    _curMis = 0;
  _misVis[cur] = true;
  _missleNodes[cur]->setPosition(_playerNode->getPosition());
  //_missleNodes[cur]->setOrientation(_playerNode->getOrientation());
  _misThrusts[cur] = _thrust+2;
}

void MyFlowSimGpu::addDRate(Ogre::Real dr)
{
  _dyeDRate += dr;
  if(_dyeDRate >= 1.0)
	  _dyeDRate = 1.0;
}